package gui;

/**
 * This class implements a table that displays and allows the user to edit the
 * permissions for a role.
 *
 * @author Aaron A. Lovato
 */
 
import backend.*;
import javax.swing.table.*;
import java.util.*;
import javax.swing.event.*;
import javax.swing.JOptionPane;
import javax.swing.*;

public class PermissionsTableModel extends AbstractTableModel 
                                implements TableModelListener
{
    private String[] columns;
    private Object[][] data;
    private Role role;
    private Server server;
    private boolean editable;
    
    public PermissionsTableModel(Server sr, Role role, boolean editable)
    {
        // Save the associated role
        this.role = role;
        this.server = sr;
        this.editable = editable;

        //Add the default values to the equation table
        columns = new String[2];
        columns[0] = "Object";
        columns[1] = "Action";
        data = new Object[0][2];
        
        int row = 0;
        if (this.role != null)
        {
            HashMap<String, Permission> perms = this.role.getPermissions();
            for(String s : perms.keySet())
            {
                Object[] newRow = new Object[2];
                newRow[0] = s;
                newRow[1] = perms.get(s).getValue();
                addRow(newRow);
            }
            
            // Add parent's permissions
            addParentPermissions(this.role);
        }

        Object[] newRow = new Object[2];
        newRow[0] = "";
        newRow[1] = "";
        addRow(newRow);
            
        addTableModelListener(this);
    }
    
    // Recursively add all of the children's permissions to the parent
    public void addParentPermissions(Role role)
    {
        Vector<Role> parents = role.getParents();

        if (parents.isEmpty()) // Base Case
            return;

        // Add permissions for this level
        for (Role parent : parents)
        {
            for(String s : parent.getPermissions().keySet())
            {
                Object[] newRow = new Object[2];
                newRow[0] = s;
                newRow[1] = parent.getPermissions().get(s).getValue();
                addRow(newRow);
            }
            addParentPermissions(parent); // Recursive magic
        }
    }
    
    public void setEditable(boolean editable)
    {
        this.editable = editable;
    }
    
    public int getColumnCount()
    {
        return columns.length;
    }
    
    public int getRowCount()
    {
        return data.length;
    }
    
    public String getColumnName(int col) 
    {
        return columns[col];
    }

    public Object getValueAt(int row, int col) 
    {
        return data[row][col];
    }
    
    public Class getColumnClass(int c) 
    {
        return getValueAt(0, c).getClass();
    }

    public boolean isCellEditable(int row, int col) 
    {
        if (!editable)
            return false;
        if(row == data.length - 1 || col == 1)
            return true;
        else
            return false;
    }

    public void setValueAt(Object value, int row, int col) 
    {
        data[row][col] = value;
        fireTableCellUpdated(row, col);
    }
    
    public void addRow(Object[] row)
    {
        // Check if we're duplicating permissions
        // Assuming we can't have names with different values.
        for (int i=0; i < data.length; i++) {
            if (data[i][0] == row[0])
                return;
        }

        int newLength = data.length + 1;
        Object[][] newData = new Object[newLength][2];
        System.arraycopy(data, 0, newData, 0, data.length);
        data = newData;
        data[newLength-1][0] = row[0];
        data[newLength-1][1] = row[1];
        fireTableRowsInserted(data.length, data.length);
    }
    
    public void tableChanged(TableModelEvent e)
    {
        //Extend the table when a new row is filled
        if(e.getType() == TableModelEvent.UPDATE && e.getFirstRow() == (data.length - 1))
        {         
            String name = (String) data[data.length-1][0];
            String value = (String) data[data.length-1][1];
            if(name == null || name.trim().compareTo("") == 0)
                return;
            try
            {
                // Don't add a permission if the value isn't set
                if (value.compareTo("") != 0)
                {
                    server.assignPermission(role.getName(), name, value);
                    addRow(new Object[2]);
                }
                
            }
            catch(Exception error)
            {
                JOptionPane.showMessageDialog(null, error.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
                data[data.length-1][0] = "";
                data[data.length-1][1] = "";                
            }            
        }
        else if(e.getColumn() == 1)
        {
            // Update the changed permission
            String name = (String) data[e.getFirstRow()][0];
            String value = (String) data[e.getFirstRow()][1];
            if(name == null || name == "")
                return;
            try
            {
                role.setPermission(name, value);
            }
            catch(Exception error)
            {
                JOptionPane.showMessageDialog(null, error.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        }
        
    }
    
    public void setRole(Role role)
    {
        this.role = role;
        data = new Object[0][2];
        
        int row = 0;
        if (this.role != null)
        {
            HashMap<String, Permission> perms = this.role.getPermissions();
            for(String s : perms.keySet())
            {
                Object[] newRow = new Object[2];
                newRow[0] = s;
                newRow[1] = perms.get(s).getValue();
                addRow(newRow);
            }
            // Add parent's permissions
            addParentPermissions(this.role);
        }

        Object[] newRow = new Object[2];
        newRow[0] = "";
        newRow[1] = "";
        addRow(newRow);

        
        fireTableDataChanged();
    }
    
    public void deleteRow(int oldRow)
    {
        // Get the name of the permission to delete
        String name = (String) data[oldRow][0];
        try
        {
            server.removePermission(role.getName(), name);
//             role.removePermission(name);
        }
        catch (Exception error)
        {
            JOptionPane.showMessageDialog(null, "Oh god how did this get here, I am not good with computer",
                                          "Error", JOptionPane.ERROR_MESSAGE, new ImageIcon("resources/cat.jpg"));
        }
        
        // Rebuild data
        data = new Object[0][2];
        
        int row = 0;
        if (this.role != null)
        {
            HashMap<String, Permission> perms = this.role.getPermissions();
            for(String s : perms.keySet())
            {
                Object[] newRow = new Object[2];
                newRow[0] = s;
                newRow[1] = perms.get(s).getValue();
                addRow(newRow);
            }
        }
        
        Object[] newRow = new Object[2];
        newRow[0] = "";
        newRow[1] = "";
        addRow(newRow);
        
        fireTableDataChanged();
    }
}

